package org.sardine.beans;

import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.sardine.beans.support.BeanObjectInstantiation;
import org.sardine.beans.support.DefaultElmBeanDefinitionRegistry;
import org.sardine.beans.support.ElmBeanDefinition;
import org.sardine.beans.support.ElmBeanDefinitionValueResolver;
import org.sardine.beans.support.ElmPropertyDefinition;
import org.sardine.util.Assert;

/**
 * @author BearBear
 *
 */
public class DefaultBeanContainer extends DefaultElmBeanDefinitionRegistry implements BeanContainer{
	
	private static final Logger log = Logger.getLogger(DefaultBeanContainer.class);
	private final BeanObjectInstantiation instantiation = new BeanObjectInstantiation();
	
	public DefaultBeanContainer(String configLocation){
		this(new String[]{configLocation});
	}
	
	public DefaultBeanContainer(String[] configLocations){
		super(configLocations);
		findBeanPostProcessor();
		instantiateAllBeans();
	}

	public Object getBean(String id) {
		Assert.notEmpty(id, "id不能为空");
		return doGetBean(id);
	}
	
	private void findBeanPostProcessor(){
		
		log.info("开始查找BeanPostProcessor的实现类配置并优先实例化");
		Map<String,ElmBeanDefinition> beanDefinitions = getBeanDefinitions();
		synchronized(beanDefinitions){
			
			Iterator<ElmBeanDefinition> it = beanDefinitions.values().iterator();
			while(it.hasNext()){
				ElmBeanDefinition ebd = it.next();
				Class beanClazz = ebd.getBeanClass();
				if(BeanPostProcessor.class.isAssignableFrom(beanClazz)){
					String postProcessorId = ebd.getId();
					BeanPostProcessor postProcessor = (BeanPostProcessor)getBean(postProcessorId);
					log.info("注册一个BeanPostProcessor，id为\""+postProcessorId+"\" 并实例化");
					registerBeanPostProcessorId(postProcessorId);
					//registerBeanPostProcessor(postProcessor);
				}
			}
		}
	}
	
	private void instantiateAllBeans(){
		log.info("开始实例化所有bean");
		Map<String,ElmBeanDefinition> beanDefinitions = getBeanDefinitions();
		synchronized(beanDefinitions){
			for(Iterator<String> it = beanDefinitions.keySet().iterator();it.hasNext();){
				String beanId = it.next();
				getBean(beanId);
			}
		}
	}
	
	
	
	/**
	 * 
	 * 根据 id 对应的 ElmBeanDefinition 的 bean 信息创建 bean 实例，并注册到 DefaultBeanRegistry 里
	 * 
	 * @param id
	 * @return
	 */
	private Object instantiateBean(String id){
		
		Assert.notEmpty(id, "id不能为空");
		
		ElmBeanDefinition beanDefinition = getElmBeanDefinition(id);
		String beanId = beanDefinition.getId();
		Object beanObject = instantiation.createObject(beanDefinition.getBeanClass());
		
		/*
		 * 注册bean实例的操作应该先于填充bean属性的操作。因为如果bean属性引用的是自己，而此时bean实例还没有注册，
		 * 那么将不断执行getBean(id)，导致抛出StackOverFlow异常。
		 * 
		 * */
		registerBeanObject(beanId,beanObject);
		
		beanObject = populateBean(beanDefinition,beanObject);
		beanObject = afterInitialization(beanId,beanObject);
		//registerBeanObject(beanId,beanObject);
		return beanObject;
	}
	
	/**
	 * 
	 * 根据 ElmBeanDefinition 的 property 信息来填充 bean 实例的属性
	 * 
	 * @param beanDefinition
	 * @param beanObject
	 * @return
	 */
	private Object populateBean(ElmBeanDefinition beanDefinition,Object beanObject){
		Assert.notNull(beanDefinition, "beanDefinition不能为空");
		Assert.notNull(beanObject, "beanObject不能为空");
		
		log.debug("开始填充id为\""+beanDefinition.getId()+"\"的实例的所有属性");
		
		BeanObjectWrapper wrapper = new BeanObjectWrapperImpl(beanDefinition.getId(),beanObject);
		
		ElmBeanDefinitionValueResolver resolver = new ElmBeanDefinitionValueResolver(this,beanObject);
		List<ElmPropertyDefinition> propertys = beanDefinition.getPropertyList();
		for(ElmPropertyDefinition property : propertys){
			
			String elmPropertyName = property.getName();
			Object elmPropertyValue = property.getValue();
			
			log.debug("开始解析<property name=\""+elmPropertyName+"\">元素定义的value属性类型");
			Object resolvedElmPropertyValue = resolver.resolveValue(elmPropertyValue);
			
			wrapper.wrapBean(elmPropertyName, resolvedElmPropertyValue);
			
		}
		
		beanObject = wrapper.getWrappedBean();
		
		
		return beanObject;
		
	}
	
	private Object afterInitialization(String beanId,Object beanObject){
		/*
		List<BeanPostProcessor> postProcessors = getBeanPostProcessors();
		for(BeanPostProcessor bpp : postProcessors){
			beanObject = bpp.postProcessAfterInitialization(beanId,beanObject);
			//registerBeanObject(beanId,beanObject);
		}
		registerBeanObject(beanId,beanObject);
		return beanObject;*/
		
		List<String> postProcessorIds = getBeanPostProcessorIds();
		Object newBean = null;
		for(String ppid : postProcessorIds){
			BeanPostProcessor bpp = (BeanPostProcessor)getBean(ppid);
			newBean = bpp.postProcessAfterInitialization(beanId,beanObject);
		}
		if(newBean != null && beanObject != newBean){
			log.info("id为\""+beanId+"\"的实例重新注册");
			registerBeanObject(beanId,newBean);
			return newBean;
		}
		//registerBeanObject(beanId,beanObject);
		return beanObject;
		
	}
	
	/**
	 * 
	 * 通过 id 查找对应的实例对象，如果不存，就根据 id 对应的 ElmBeanDefinition 的 bean 信息创建 bean 实例
	 * 
	 * @param id 实例对象的id
	 * @return
	 */
	private Object doGetBean(final String id){
		
		Assert.notEmpty(id, "id不能为空");
		
		Object obj = getBeanObject(id);
		if(obj != null){
			log.debug("id为\""+id+"\"的bean实例已经存在，直接返回");
			return obj;
		}else{
			log.debug("id为\""+id+"\"的bean实例不存在，将尝试创建");
			obj = tryGetBeanObject(id,new ObjectFactory(){

				public Object getObject() {
					return instantiateBean(id);
				}
			});
		}
		return obj;
		
	}
	
	

}
